package me.kuye.jkuye.plugin.activerecord;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import me.kuye.jkuye.plugin.activerecord.cache.ICache;
import me.kuye.jkuye.plugin.activerecord.dialect.Dialect;
import me.kuye.jkuye.plugin.activerecord.dialect.MySqlDialect;
import me.kuye.jkuye.util.StringUtil;

public class Config {
	private final ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
	private String name;
	private DataSource dataSource;
	int transactionLevel = Connection.TRANSACTION_READ_COMMITTED;
	boolean devMode = false;
	boolean showSql = false;
	Dialect dialect = new MySqlDialect();
	IContainerFactory containerFactory = new IContainerFactory() {
		public Map<String, Object> getAttrsMap() {
			return new HashMap<String, Object>();
		}

		public Map<String, Object> getColumnsMap() {
			return new HashMap<String, Object>();
		}

		public Set<String> getModifyFlagSet() {
			return new HashSet<String>();
		}
	};
	private ICache cache;

	public Config() {
	}

	public Config(String name, DataSource dataSource) {
		if (StringUtil.isEmpty(name)) {
			throw new IllegalArgumentException(" the config name is can not be null");
		}
		if (dataSource == null) {
			throw new IllegalArgumentException(" the datasource is can not be null");
		}
		this.name = name.trim();
		this.dataSource = dataSource;
	}

	public Config(String name, DataSource dataSource, Dialect dialect) {
		if (StringUtil.isEmpty(name)) {
			throw new IllegalArgumentException(" the config name can not be null");
		}
		if (dataSource == null) {
			throw new IllegalArgumentException(" the dataSource is can not be bull");
		}
		if (dialect == null) {
			throw new IllegalArgumentException(" the dialect is can not be null");
		}

		this.name = name.trim();
		this.dataSource = dataSource;
		this.dialect = dialect;
	}

	public Config(String name, DataSource dataSource, Dialect dialect, Boolean devMode, Boolean showSql,
			Integer transactionLevel, IContainerFactory containerFactory, ICache cache) {
		if (StringUtil.isEmpty(name))
			throw new IllegalArgumentException("Config name can not be blank");
		if (dataSource == null)
			throw new IllegalArgumentException("DataSource can not be null");

		this.name = name.trim();
		this.dataSource = dataSource;

		if (dialect != null)
			this.dialect = dialect;
		if (showSql != null)
			this.showSql = showSql;
		if (devMode != null)
			this.devMode = devMode;
		if (transactionLevel != null)
			this.transactionLevel = transactionLevel;
		if (containerFactory != null)
			this.containerFactory = containerFactory;
		if (cache != null)
			this.cache = cache;
	}

	public final void setThreadLocalConnection(Connection connection) {
		threadLocal.set(connection);
	}

	public final void removeThreadLocalConnection() {
		threadLocal.remove();
	}

	public final Connection getThreadLocalConnection() {
		return threadLocal.get();
	}

	public Connection getConnection() throws SQLException {
		Connection connection = threadLocal.get();
		if (connection != null) {
			return connection;
		}
		return showSql ? new SqlReporter(dataSource.getConnection()).getConnection() : dataSource.getConnection();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public int getTransactionLevel() {
		return transactionLevel;
	}

	public void setTransactionLevel(int transactionLevel) {
		this.transactionLevel = transactionLevel;
	}

	public boolean isDevMode() {
		return devMode;
	}

	public void setDevMode(boolean devMode) {
		this.devMode = devMode;
	}

	public boolean isShowSql() {
		return showSql;
	}

	public void setShowSql(boolean showSql) {
		this.showSql = showSql;
	}

	public Dialect getDialect() {
		return dialect;
	}

	public void setDialect(Dialect dialect) {
		this.dialect = dialect;
	}

	public IContainerFactory getContainerFactory() {
		return containerFactory;
	}

	public void setContainerFactory(IContainerFactory containerFactory) {
		this.containerFactory = containerFactory;
	}

	public ICache getCache() {
		return cache;
	}

	public void setCache(ICache cache) {
		this.cache = cache;
	}

	public ThreadLocal<Connection> getThreadLocal() {
		return threadLocal;
	}

	public void colse(Connection connection) {
		if (threadLocal.get() == null) {
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					throw new ActiveRecordException(e);
				}
			}
		}
	}

}
